package repo

import (
	"fmt"
	"git.multiverse.io/eventkit/dxc-server/config"
	"git.multiverse.io/eventkit/dxc-server/models"
	"sync"
)

var (
	ins  Repository
	once sync.Once
)

type TxnRepositoryType int

const (
	Memory                        = "memory"
	Redis                         = "redis"
	Hazelcast                     = "Hazelcast"
	Hybrid_With_Redis_Storage     = "hybridWithRedis"
	Hybrid_With_Hazelcast_Storage = "hybridWithHazelcast"
)

// @Desc a interface to operate transaction parameters
type Repository interface {
	AddRoot(transaction *models.Transaction) (int, error)
	AddBranch(transaction *models.Transaction) (int, error)
	Recovery(root *models.RootTransaction) (int, error)
	FindAllBranchByRootXid(rootXid string) (*models.RootTransaction, error)
	DeleteTxn(rootXid string) (int, error)
	IsExistsRootTransaction(rootXid string) (bool, error)
	IsExistsBranchTransaction(rootXid string, branchXid string) (bool, error)
	TryCallback(rootXid string, callbackType string) (*models.RootTransaction, error)
	TryEnList(rootXid string) error
	CallbackFail(rootXid string, branches []*models.Transaction, firstTimeCallback bool) (int, error)
	FindRootBranchesByTimeExpire(expireSeconds int64) (rootXIds []*models.Transaction, err error)
	UpdateBranchTryFailedIgnoreCallbackCancel(rootXid string, branchXid string) (int, error)
	ExpireTime(rootXid string) (int, error)
	LoadRootsFromPersistenceRepo(count int64) ([]string, error)
}

// @Desc new a Repository instance in MEMORY mode
func RepositoryInstance() Repository {
	repoType := config.Cfg.Repo.Type
	once.Do(func() {
		ins = NewTxnRepositoryFactory().CreateTxnRepository(repoType)
	})
	return ins
}

type RepositoryFactory struct{}

// @Desc new a RepositoryFactory
func NewTxnRepositoryFactory() *RepositoryFactory {
	return &RepositoryFactory{}
}

// @Desc new a Repository in MEMORY mode
func (t *RepositoryFactory) CreateTxnRepository(repositoryType string) Repository {
	switch repositoryType {
	case Memory:
		return NewMemoryTxnRepository()
	case Hybrid_With_Redis_Storage, Hybrid_With_Hazelcast_Storage:
		return NewHybridStorage(repositoryType)
	default:
		panic(fmt.Sprintf("Not support transaction repository type `%s`, please check", repositoryType))
	}
}
